package net.sf.rose.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;

import net.sf.rose.boot.BootStrap;

/**
 * 进程管理
 * 
 * @author fengjian
 *
 */
public class ProcessManager {

	/**
	 * 获取当前进程的PID
	 * @return 当前进程的PID
	 */
	public String getPid() {
		String name = ManagementFactory.getRuntimeMXBean().getName();
		return name.split("@")[0];
	}

	/**
	 * 根据进程所占的端口号杀死进程
	 * @param port 要杀死进程所占用的端口号
	 * @return 进程的PID
	 */
	public String kill(int port) {
		Runtime runtime = Runtime.getRuntime();
		try {
			if (BootStrap.isWindows()) {
				// 查找进程号
				Process p = runtime.exec("cmd /c netstat -ano | findstr \"" + port + "\"");
				InputStream in = p.getInputStream();
				List<String> data = new ArrayList<>();
				BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
				String line;
				while ((line = reader.readLine()) != null) {
					data.add(line);
				}
				reader.close();
				p.destroy();
				String pid = null;
				// 过滤指定端口的进程号
				// 验证此行是否为指定的端口，因为 findstr命令会是把包含的找出来，例如查找80端口，但是会把8099查找出来
				Pattern pattern = Pattern.compile("^ *[a-zA-Z]+ +\\S+");
				for (String str : data) {
					Matcher matcher = pattern.matcher(str);
					matcher.find();
					String find = matcher.group();
					int spstart = find.lastIndexOf(":");
					find = find.substring(spstart + 1);
					try {
						int _port = Integer.parseInt(find);
						if (_port == port) {
							int offset = str.lastIndexOf(" ");
							str = str.substring(offset);
							str = str.trim();
							pid = str;
							break;
						}
					} catch (NumberFormatException e) {
					}
				}
				if (pid != null) {
					return kill(pid);
				} else {
					return "search process by port(" + port + ") is not success...";
				}
			} else {
				return "linux system is not realized...";
			}
		} catch (IOException e) {
			throw new RoseRuntimeException(e);
		}
	}

	/**
	 * 杀死进程
	 * @param pid 要杀死进程的PID
	 * @return 进程的PID
	 */
	public String kill(String pid) {
		try {
			Process p = null;
			if (BootStrap.isWindows()) {
				p = Runtime.getRuntime().exec("taskkill /F /pid " + pid);
			} else {
				p = Runtime.getRuntime().exec("kill -9 " + pid);
			}
			InputStream inputStream = p.getInputStream();
			String txt = readTxt(inputStream, "GBK");
			p.destroy();
			return txt;
		} catch (Exception e) {
			return e.getMessage();
		}
	}

	/**
	 * 杀死进程
	 * @param process - 进程引用
	 * @return 被杀死进程的PID
	 */
	public String kill(Process process) {
		try {
			Field f = process.getClass().getDeclaredField("handle");
			f.setAccessible(true);
			long handl = f.getLong(process);
			Kernel32 kernel = Kernel32.INSTANCE;
			WinNT.HANDLE handle = new WinNT.HANDLE();
			handle.setPointer(Pointer.createConstant(handl));
			int ret = kernel.GetProcessId(handle);
			Long PID = Long.valueOf(ret);
			return kill(PID + "");
		} catch (Exception e) {
			return e.getMessage();
		}
	}

	private String readTxt(InputStream in, String charset) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(in, charset));
		StringBuffer sb = new StringBuffer();
		String line;
		while ((line = reader.readLine()) != null) {
			sb.append(line);
		}
		reader.close();
		return sb.toString();
	}

	public static void main(String[] args) {
		BootStrap.simpleInit();
		ProcessManager pm = new ProcessManager();
		System.out.println(pm.kill(9980));
	}

}
